﻿using Entity;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Nest;
using ServiceCore.Token;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static ServiceCore.Tool.ES.es_cloud_product;

namespace ServiceCore.Tool.ES
{

    public interface Ies_cloud_product
    {
        /// <summary>
        /// 数据添加
        /// </summary>
        /// <param name="logmod"></param>
        /// <returns></returns>
        object Add_Item(cloud_product logmod);
        /// <summary>
        /// 数据更新
        /// </summary>
        /// <param name="update_mod"></param>
        /// <returns></returns>
        object Update_row(cloud_product update_mod);
        /// <summary>
        /// 查询符合条件的项
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        object Es_query(cloud_product_search query, string uid, Func<IReadOnlyCollection<IHit<cloud_product>>, string, bool> outinfo);
        object Es_delete(string Id);
        /// <summary>
        /// 根据ID获取文章信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        cloud_product get_es_model(string id);
        /// <summary>
        /// 自定义条件获取
        /// </summary>
        /// <param name="selector"></param>
        /// <returns></returns>
        cloud_product get_es_model(Func<BoolQueryDescriptor<cloud_product>, IBoolQuery> selector);
    }
    public class es_cloud_product: Ies_cloud_product
    {
        private ConnectionSettings setting_Config
        {
            get
            {
                var uri = new Uri(AppSettingConfig["ES_cloud_product:uri"].ToString());
                var settings = new ConnectionSettings(uri);
                //禁用ping 第一次使用节点或使用被标记死亡的节点进行ping
                settings.DisablePing(false);
                //调试信息
                settings.DisableDirectStreaming(true);
                //抛出异常 默认false，错误信息在每个操作的response中
                settings.ThrowExceptions(true);

                return settings;
            }
        }
        private ElasticClient ES_client = null;// new ElasticClient(setting_Config);
        private Es_Web_Set EsWebSet = new Es_Web_Set();
        /// <summary>
        /// 定义ES当前使用的index和type设定
        /// </summary>
        private class Es_Web_Set
        {
            /// <summary>
            /// ES 索引
            /// </summary>
            public string Index { get; set; }
            /// <summary>
            /// ES类型
            /// </summary>
            public string Type { get; set; }
            /// <summary>
            /// 别名
            /// </summary>
            public string Alias { get; set; }
        }

        public string ES_IndexAndType_Set { get { return AppSettingConfig["ES_cloud_product:I_T"].ToString(); } }
        private readonly IConfiguration AppSettingConfig;
        private readonly ISnowflake_Helper _getid;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ITokenUser_Service _user;
        public es_cloud_product(IConfiguration configuration, ISnowflake_Helper getid, IHttpContextAccessor httpContextAccessor, ITokenUser_Service user)
        {
            AppSettingConfig = configuration;
            _getid = getid;
            _httpContextAccessor = httpContextAccessor;
            _user = user;
            if (ES_client == null)
            {
                ES_client = new ElasticClient(setting_Config);
            }
            var es_web = ES_IndexAndType_Set.Split(':');
            EsWebSet.Index = es_web[0];
            EsWebSet.Type = es_web[1];
            EsWebSet.Alias = es_web[2];
        }

        /// <summary>
        /// 定义log文件模型
        /// </summary>
        [ElasticsearchType(Name = "cloud_product", IdProperty = "Id")]
        public class cloud_product
        {
            [Keyword(Name = "Id", Index = true)]
            public string Id { get; set; }
            /// <summary>
            /// 图片地址
            /// </summary>
            [Keyword(Name = "Img", Index = false)]
            public string Img { get; set; }
            /// <summary>
            /// 缩略图
            /// </summary>
            [Keyword(Name = "thumbnail", Index = false)]
            public string thumbnail { get; set; }
            [Keyword(Name = "pic_des", Index = false)]
            /// <summary>
            /// 图集
            /// </summary>
            public string pic_des { get; set; }
            /// <summary>
            /// 商品名称
            /// </summary>
            [Text(Name = "Name", Index = true, Analyzer = "jieba_index", SearchAnalyzer = "jieba_index")]
            public string Name { get; set; }
            /// <summary>
            /// 商品简介
            /// </summary>
            [Text(Name = "Des", Index = true, Analyzer = "jieba_index", SearchAnalyzer = "jieba_index")]
            public string Des { get; set; }
            /// <summary>
            /// 关键字
            /// </summary>
            [Text(Name = "Keyword", Index = true, Analyzer = "jieba_index", SearchAnalyzer = "jieba_index")]
            public string Keyword { get; set; }
            /// <summary>
            ///  聚合其他搜索项
            /// </summary>
            [Text(Name = "other_search", Index = true, Analyzer = "jieba_index", SearchAnalyzer = "jieba_index")]
            public string other_search { get; set; }
            [Number(NumberType.Double, Name = "Pirce")]
            /// <summary>
            /// 图集
            /// </summary>
            public double? Price { get; set; }
            /// <summary>
            /// 商品类型ID
            /// </summary>
            [Keyword(Name = "CategoryId", Index = true)]
            public string CategoryId { get; set; }
            /// <summary>
            /// 商品类型名称
            /// </summary>
            [Keyword(Name = "Category_name", Index = true)]
            public string Category_name { get; set; }
            /// <summary>
            ///  条码
            /// </summary>
            [Keyword(Name = "codeBar", Index = true)]
            public string codeBar { get; set; }
            /// <summary>
            /// 品牌
            /// </summary>
            [Keyword(Name = "Brand", Index = true)]
            public string Brand { get; set; }
            /// <summary>
            /// 型号 口味
            /// </summary>
            [Keyword(Name = "Type", Index = false)]
            public string Type { get; set; }
            /// <summary>
            /// 规格
            /// </summary>
            [Keyword(Name = "Spec", Index = false)]
            public string Spec { get; set; }

            [Number(NumberType.Double, Name = "Def_Cost")]
            /// <summary>
            /// 成本价
            /// </summary>
            public double? Def_Cost { get; set; }

            [Keyword(Name = "TemplateContent", Index = false)]
            /// <summary>
            /// 模板内容
            /// </summary>
            public string TemplateContent { get; set; }
            [Keyword(Name = "StructureContent", Index = false)]
            /// <summary>
            /// 实际内容
            /// </summary>
            public string StructureContent { get; set; }
            /// <summary>
            ///  添加人
            /// </summary>
            [Keyword(Name = "add_user", Index = true)]
            public string add_user { get; set; }
            /// <summary>
            /// 添加时间
            /// </summary>
            [Date(Name = "add_time", Index = true)]
            public DateTime add_time { get; set; }
            /// <summary>
            /// 是否公有库数据
            /// </summary>
            [Boolean(Name = "is_rk_cloud", Index = true)]
            public bool? is_rk_cloud { get; set; }
            /// <summary>
            ///  所属商户
            /// </summary>
            [Keyword(Name = "baseuserid", Index = true)]
            public string baseuserid { get; set; }
            /// <summary>
            ///  旧的指向关键参数
            /// </summary>
            [Keyword(Name = "old_params", Index = true)]
            public string old_params { get; set; }
            /// <summary>
            /// 额外参数项
            /// </summary>
            [Keyword(Name = "ext_params", Index = true)]
            public string ext_params { get; set; }
            /// <summary>
            /// 商品状态 0禁用 1启用
            /// </summary>
            [Number(NumberType.Integer, Name = "product_state")]
            public int product_state { get; set; }

            /// <summary>
            /// 如果是从云商品里拽出来的数据，则存在该字段, 如果是自己添加的 则该字段为自己的ID
            /// </summary>
            [Keyword(Name = "source_id", Index = false)]
            public string source_id { get; set; }
            /// <summary>
            /// 编辑时间
            /// </summary>
            [Date(Name = "edit_time", Index = true)]
            public DateTime edit_time { get; set; }
        }

        /// <summary>
        /// 添加日志信息  如果index不存在 则创建一个新的
        /// </summary>
        public object Add_Item(cloud_product item_mod)
        {
            try
            {

                if (!ES_client.IndexExists(EsWebSet.Index).Exists)
                {
                    //基本配置
                    IIndexState indexState = new IndexState()
                    {
                        Settings = new IndexSettings()
                        {
                            NumberOfReplicas = 0,//副本数 因为目前都是单节点在跑  也没有服务器做这个架构
                            NumberOfShards = 5,//分片数

                        }
                    };
                    //创建并Mapping
                    var create = ES_client.CreateIndex(EsWebSet.Index, p =>
                            p.InitializeUsing(indexState)
                            .Mappings(m => m.Map<cloud_product>(mp => mp.AutoMap())).Aliases(s => s.Alias(EsWebSet.Alias)));

                }
                item_mod.other_search = $"{item_mod.Category_name},{item_mod.Brand},{item_mod.Spec},{item_mod.Type}";
                //写入数据，指定索引
                var result = ES_client.Index(item_mod, s => s.Index(EsWebSet.Index).Type(EsWebSet.Type).Id(item_mod.Id).Refresh(Elasticsearch.Net.Refresh.True));
                return new
                {
                    result.Shards,
                    result.ApiCall.HttpStatusCode,
                    result.DebugInformation,
                    result.ServerError
                };
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public cloud_product get_es_model(string id)
        {
            try
            {
                var result = ES_client.Search<cloud_product>(s =>
                {
                    return s.Index(EsWebSet.Index).Type(EsWebSet.Type).Query(a =>
                    {
                        return a.Bool(z => z.Must(sq => sq.Term(c => c.Field(d => d.Id).Value(id))));
                    })
                    .From(0) //跳过的数据个数
                    .Size(1);//返回数据个数
                });
                return result.Documents.FirstOrDefault();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public cloud_product get_es_model(Func<BoolQueryDescriptor<cloud_product>, IBoolQuery> selector)
        {
            try
            {
                var result = ES_client.Search<cloud_product>(s =>
                {
                    return s.Index(EsWebSet.Index).Type(EsWebSet.Type).Query(a =>
                    {
                        return a.Bool(selector);
                    })
                    .From(0) //跳过的数据个数
                    .Size(1);//返回数据个数
                });
                return result.Documents.FirstOrDefault();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 更新信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="update_mod"></param>
        /// <returns></returns>
        public object Update_row(cloud_product update_mod)
        {
            try
            {
                DocumentPath<cloud_product> deletePath = new DocumentPath<cloud_product>(update_mod.Id).Index(EsWebSet.Index).Type(EsWebSet.Type);
                var response = ES_client.Update(deletePath, (p) => p.Doc(update_mod).Refresh(Elasticsearch.Net.Refresh.True));
                return new
                {
                    response.ShardsHit,
                    response.ApiCall.HttpStatusCode,
                    response.DebugInformation,
                    response.ServerError
                };
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 查询符合条件的数据
        /// </summary>
        /// <param name="query">搜索条件</param>
        /// <param name="uid">定义额外项</param>
        /// <param name="have_p_list">入参已经加入商品库的数据列表</param>
        /// <returns></returns>
        public object Es_query(cloud_product_search query, string uid, Func<IReadOnlyCollection<IHit<cloud_product>>, string, bool> outinfo)
        {
            try
            {
                string search_key = "";
                if (!string.IsNullOrWhiteSpace(query.search_key))
                {
                    search_key = Regex.Replace(query.search_key, @"\s", "");//去掉搜索字符串中的奇奇怪怪的东西 
                }
                //设置must条件
                var mustQuerys = new List<Func<QueryContainerDescriptor<cloud_product>, QueryContainer>>();
                var must_not_Querys = new List<Func<QueryContainerDescriptor<cloud_product>, QueryContainer>>();
                if (!string.IsNullOrWhiteSpace(search_key))
                {
                    mustQuerys.Add(
                       sq => sq.Match(b => b.Analyzer("jieba_index").Field(c => c.Name).Query(search_key))
                    || sq.Match(b => b.Analyzer("jieba_index").Field(c => c.Des).Query(search_key))
                    || sq.Match(b => b.Analyzer("jieba_index").Field(c => c.other_search).Query(search_key))
                    || sq.Match(b => b.Analyzer("jieba_index").Field(c => c.Keyword).Query(search_key))
                    );
                }
                if (!string.IsNullOrWhiteSpace(query.CategoryId))
                {
                    mustQuerys.Add(sq => sq.Term(a => a.Field(c => c.CategoryId).Value(query.CategoryId)));
                }
                if (!string.IsNullOrWhiteSpace(query.codeBar))
                {
                    mustQuerys.Add(sq => sq.Term(a => a.Field(c => c.codeBar).Value(query.codeBar)));
                } 
                if (query.iscloud.HasValue)
                {
                    mustQuerys.Add(sq => sq.Term(a => a.Field(c => c.is_rk_cloud).Value(true)));
                }
                if (!string.IsNullOrWhiteSpace(uid))
                {
                    mustQuerys.Add(sq => sq.Term(a => a.Field(c => c.add_user).Value(uid)));
                }
                if (query.have_codebar.HasValue)
                {
                    if (query.have_codebar.Value)
                    {
                        must_not_Querys.Add(sq => sq.Term(a => a.Field(c => c.codeBar).Value("none")));
                    }
                    else {
                        mustQuerys.Add(sq => sq.Term(a => a.Field(c => c.codeBar).Value("none")));
                    }
                }

                if (query.start_addtime.HasValue)
                {
                    mustQuerys.Add(sq => sq.DateRange(a => a.Field(c => c.add_time).GreaterThanOrEquals(query.start_addtime.Value)));
                }
                if (query.end_addtime.HasValue)
                {
                    mustQuerys.Add(sq => sq.DateRange(a => a.Field(c => c.add_time).LessThanOrEquals(query.end_addtime.Value)));
                }
                if (query.start_edittime.HasValue)
                {
                    mustQuerys.Add(sq => sq.DateRange(a => a.Field(c => c.edit_time).GreaterThanOrEquals(query.start_edittime.Value)));
                }
                if (query.end_edittime.HasValue)
                {
                    mustQuerys.Add(sq => sq.DateRange(a => a.Field(c => c.edit_time).LessThanOrEquals(query.end_edittime.Value)));
                }
                //排序
                Func<SortDescriptor<cloud_product>, IPromise<IList<ISort>>> sortDesc = sd =>
                {
                    if (!string.IsNullOrWhiteSpace(query.search_key))
                    {
                        //根据分值排序
                        sd.Descending(SortSpecialField.Score);
                    }
                    if (!string.IsNullOrWhiteSpace(query.order_column))
                    {
                        if (query.isdesc.Value)
                        {
                            sd.Descending(new Field(query.order_column));
                        }
                        else
                        {
                            sd.Ascending(new Field(query.order_column));
                        }
                    }
                    else
                    {
                        //排序 
                        sd.Ascending(d => d.edit_time);
                    }
                    return sd;
                };
                //设置高亮
                var hight_params = new Func<HighlightFieldDescriptor<cloud_product>, IHighlightField>[] {
                     new Func<HighlightFieldDescriptor<cloud_product>, IHighlightField>(c =>
                    {
                        return c.Field(d => d.Name).FragmentSize(50).PreTags("<span style='color:red;'>").PostTags("</span>");  //.Type(HighlighterType.Plain);
                    }),
                     new Func<HighlightFieldDescriptor<cloud_product>, IHighlightField>(c =>
                    {
                        return c.Field(d => d.Des).FragmentSize(64).PreTags("<span style='color:red;'>").PostTags("</span>");  //.Type(HighlighterType.Plain);
                    }),
                    new Func<HighlightFieldDescriptor<cloud_product>, IHighlightField>(c =>
                    {
                        return c.Field(d => d.other_search).FragmentSize(64).PreTags("<span style='color:red;'>").PostTags("</span>");  //.Type(HighlighterType.Plain);
                    }),
                    new Func<HighlightFieldDescriptor<cloud_product>, IHighlightField>(c =>
                    {
                        return c.Field(d => d.Keyword).FragmentSize(64).PreTags("<span style='color:red;'>").PostTags("</span>");  //.Type(HighlighterType.Plain);
                    }),
                };
                var result = ES_client.Search<cloud_product>(s =>
                {
                    return s.Index(EsWebSet.Index).Type(EsWebSet.Type).Query(a =>
                    {
                        return a.Bool(z => z.Must(mustQuerys).MustNot(must_not_Querys));
                    })
                    .Highlight(a => a.Fields(hight_params))
                    .Sort(sortDesc)
                    .From((query.page - 1) * query.pagesize) //跳过的数据个数
                    .Size(query.pagesize);//返回数据个数
                });
                var result_list = from o in result.Hits
                                  select new
                                  {
                                      Name_Hightlights = !o.Highlights.Where(s => s.Key == "Name").Any() ? o.Source.Name :
                                                   o.Highlights.Where(s => s.Key == "Name").FirstOrDefault().Value.Highlights.Any() ?
                                                      string.IsNullOrWhiteSpace(string.Join("|", o.Highlights.Where(s => s.Key == "Name").FirstOrDefault().Value.Highlights)) ?
                                                           o.Source.Name : string.Join("|", o.Highlights.Where(s => s.Key == "Name").FirstOrDefault().Value.Highlights)//.FirstOrDefault()
                                                           : o.Source.Name,
                                      other_search_Highlights = !o.Highlights.Where(s => s.Key == "other_search").Any() ? "" :
                                                   o.Highlights.Where(s => s.Key == "other_search").FirstOrDefault().Value.Highlights.Any() ?
                                                       string.Join(",", o.Highlights.Where(s => s.Key == "other_search").FirstOrDefault().Value.Highlights) : "",
                                      Des_Highlights = !o.Highlights.Where(s => s.Key == "Des").Any() ? "" :
                                                   o.Highlights.Where(s => s.Key == "Des").FirstOrDefault().Value.Highlights.Any() ?
                                                       string.Join(",", o.Highlights.Where(s => s.Key == "Des").FirstOrDefault().Value.Highlights) : "",
                                      o.Score,
                                      o.Source.Name,
                                      o.Source.Category_name,
                                      o.Source.CategoryId,
                                      o.Source.add_time,
                                      o.Source.Id,
                                      o.Source.Brand,
                                      o.Source.Spec,
                                      o.Source.baseuserid,
                                      codeBar = (o.Source.codeBar == "none" ? "" : o.Source.codeBar),
                                      o.Source.Price,
                                      o.Source.Des,
                                      o.Source.ext_params,
                                      o.Source.old_params,
                                      o.Source.pic_des,
                                      o.Source.Img,
                                      o.Source.thumbnail,
                                      o.Source.is_rk_cloud,
                                      o.Source.StructureContent,
                                      o.Source.TemplateContent,
                                      o.Source.Type,
                                      o.Source.Def_Cost,
                                      o.Source.edit_time,
                                      product_source = o.Source.is_rk_cloud.Value ? "云商品库" : "商户商品库",
                                      o.Source.other_search,
                                      in_my_stock = outinfo(result.Hits, o.Source.Id)
                                  };
                return new
                {
                    result.Total,
                    rows = result_list
                };
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 删除知识库数据 
        /// </summary>
        /// <param name="Id"></param>
        public object Es_delete(string id)
        {
            try
            {
                DocumentPath<cloud_product> deletePath = new DocumentPath<cloud_product>(id).Index(EsWebSet.Index).Type(EsWebSet.Type);
                IDeleteResponse deleresult = ES_client.Delete(deletePath, s => s.Refresh(Elasticsearch.Net.Refresh.True));
                return new
                {
                    deleresult.Shards,
                    deleresult.ApiCall.HttpStatusCode,
                    deleresult.DebugInformation,
                    deleresult.ServerError
                };
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
         
    }
}
